From 18bd44fa0d59dbc12dd5ed9aedbbc06749a88ad8 Mon Sep 17 00:00:00 2001 From: Tim Deegan Date: Thu, 15 Mar 2012 15:20:37 +0000 Subject: [PATCH] arm: don't use atomic operations to gate non-boot CPUs Since the cache is not enabled that early, better not to rely on load-linked/store-conditional. Instead, have the boot CPU call the other CPUs by their IDs, just like we do later for proper CPU bringup. Signed-off-by: Tim Deegan Committed-by: Ian Campbell --- xen/arch/arm/head.S | 26 +++++++------------------- xen/arch/arm/setup.c | 27 +++------------------------ xen/arch/arm/smpboot.c | 36 ++++++++++++++++++++++++++++++++---- xen/include/asm-arm/smp.h | 6 ++++++ 4 files changed, 48 insertions(+), 47 deletions(-) diff --git a/xen/arch/arm/head.S b/xen/arch/arm/head.S index 4b05bcd820..eabb403dfc 100644 --- a/xen/arch/arm/head.S +++ b/xen/arch/arm/head.S @@ -71,16 +71,13 @@ start: bics r12, r0, #(0xff << 24) /* Mask out flags to get CPU ID */ beq boot_cpu /* If we're CPU 0, boot now */ - /* Non-boot CPUs wait here to be woken up one at a time. - * This is basically an open-coded spin-lock to serialize. */ - ldr r0, =boot_gate /* VA of gate */ - add r0, r0, r10 /* PA of gate */ - mov r1, #1 /* (1 == locked) */ + /* Non-boot CPUs wait here to be woken up one at a time. */ 1: wfe - ldrex r2, [r0] /* Linked read of current value */ - teq r2, #0 /* (0 == unlocked) */ - strexeq r2, r1, [r0] /* Matching update -> locked */ - teq r2, #0 /* (0 == succeeded) */ + dsb + ldr r0, =smp_up_cpu /* VA of gate */ + add r0, r0, r10 /* PA of gate */ + ldr r1, [r0] /* Which CPU is being booted? */ + teq r1, r12 /* Is it us? */ bne 1b boot_cpu: @@ -270,16 +267,7 @@ paging: teq r12, #0 beq launch - /* Signal the next non-boot CPU to come and join us here */ - ldr r0, =boot_gate /* VA of gate */ - add r0, r0, r10 /* PA of gate */ - mov r1, #0 /* (0 == unlocked) */ - str r1, [r0] - dsb - isb - sev - - /* Move on to the relocated pagetables */ + /* Non-boot CPUs need to move on to the relocated pagetables */ mov r0, #0 ldr r4, =boot_httbr /* VA of HTTBR value stashed by CPU 0 */ add r4, r4, r10 /* PA of it */ diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c index fa994c3f86..777f8fb144 100644 --- a/xen/arch/arm/setup.c +++ b/xen/arch/arm/setup.c @@ -38,11 +38,6 @@ #include #include "gic.h" -/* Spinlock for serializing CPU bringup */ -unsigned long __initdata boot_gate = 1; -/* Number of non-boot CPUs ready to enter C */ -unsigned long __initdata ready_cpus = 0; - static __attribute_used__ void init_done(void) { free_init_memory(); @@ -152,8 +147,6 @@ void __init start_xen(unsigned long boot_phys_offset, void *fdt; size_t fdt_size; int cpus, i; - paddr_t gate_pa; - unsigned long *gate; fdt = (void *)BOOT_MISC_VIRT_START + (atag_paddr & ((1 << SECOND_SHIFT) - 1)); @@ -169,25 +162,11 @@ void __init start_xen(unsigned long boot_phys_offset, console_init_preirq(); #endif - percpu_init_areas(); - set_processor_id(0); /* needed early, for smp_processor_id() */ - cpus = gic_init(); + make_cpus_ready(cpus, boot_phys_offset); - printk("Waiting for %i other CPUs to be ready\n", cpus - 1); - /* Bring the other CPUs up to paging before the original - * copy of .text gets overwritten. We need to use the unrelocated - * copy of boot_gate as that's the one the others can see. */ - gate_pa = ((unsigned long) &boot_gate) + boot_phys_offset; - gate = map_domain_page(gate_pa >> PAGE_SHIFT) + (gate_pa & ~PAGE_MASK); - *gate = 0; - unmap_domain_page(gate); - /* Now send an event to wake the first non-boot CPU */ - asm volatile("dsb; isb; sev"); - /* And wait for them all to be ready. */ - while ( ready_cpus + 1 < cpus ) - smp_rmb(); - + percpu_init_areas(); + set_processor_id(0); /* needed early, for smp_processor_id() */ __set_current((struct vcpu *)0xfffff000); /* debug sanity */ idle_vcpu[0] = current; diff --git a/xen/arch/arm/smpboot.c b/xen/arch/arm/smpboot.c index f369d70f4c..4288710c97 100644 --- a/xen/arch/arm/smpboot.c +++ b/xen/arch/arm/smpboot.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -41,11 +42,17 @@ static unsigned char __initdata cpu0_boot_stack[STACK_SIZE] /* Pointer to the stack, used by head.S when entering C */ unsigned char *init_stack = cpu0_boot_stack; +/* Shared state for coordinating CPU bringup */ +unsigned long smp_up_cpu = 0; +static bool_t cpu_is_dead = 0; + +/* Number of non-boot CPUs ready to enter C */ +unsigned long __initdata ready_cpus = 0; + void __init smp_prepare_cpus (unsigned int max_cpus) { int i; - set_processor_id(0); /* needed early, for smp_processor_id() */ cpumask_clear(&cpu_online_map); cpumask_set_cpu(0, &cpu_online_map); @@ -56,9 +63,30 @@ smp_prepare_cpus (unsigned int max_cpus) cpumask_copy(&cpu_present_map, &cpu_possible_map); } -/* Shared state for coordinating CPU bringup */ -unsigned long smp_up_cpu = 0; -static bool_t cpu_is_dead = 0; +void __init +make_cpus_ready(unsigned int max_cpus, unsigned long boot_phys_offset) +{ + unsigned long *gate; + paddr_t gate_pa; + int i; + + printk("Waiting for %i other CPUs to be ready\n", max_cpus - 1); + /* We use the unrelocated copy of smp_up_cpu as that's the one the + * others can see. */ + gate_pa = ((paddr_t) (unsigned long) &smp_up_cpu) + boot_phys_offset; + gate = map_domain_page(gate_pa >> PAGE_SHIFT) + (gate_pa & ~PAGE_MASK); + for ( i = 1; i < max_cpus; i++ ) + { + /* Tell the next CPU to get ready */ + /* TODO: handle boards where CPUIDs are not contiguous */ + *gate = i; + asm volatile("dsb; isb; sev"); + /* And wait for it to respond */ + while ( ready_cpus < i ) + smp_rmb(); + } + unmap_domain_page(gate); +} /* Boot the current CPU */ void __cpuinit start_secondary(unsigned long boot_phys_offset, diff --git a/xen/include/asm-arm/smp.h b/xen/include/asm-arm/smp.h index 8099f6da4f..a98032dc2c 100644 --- a/xen/include/asm-arm/smp.h +++ b/xen/include/asm-arm/smp.h @@ -16,6 +16,12 @@ DECLARE_PER_CPU(cpumask_var_t, cpu_core_mask); extern void stop_cpu(void); +/* Bring the non-boot CPUs up to paging and ready to enter C. + * Must be called after Xen is relocated but before the original copy of + * .text gets overwritten. */ +extern void +make_cpus_ready(unsigned int max_cpus, unsigned long boot_phys_offset); + #endif /* * Local variables: -- 2.30.2